/***************************************************************************
* Copyright  Faraday Technology Corp 2002-2003.  All rights reserved.      *
*--------------------------------------------------------------------------*
* Name:irq.c                                                               *
* Description: IRQ Interrupt routine                                       *
* Author:                                                       *
****************************************************************************/
#include "unione_lite.h"
#include "interrupt.h"

volatile UINT32 *IRQBase = (UINT32 *)INTC_FTINTC020_PA_BASE;	

fLib_INT IRQVector[PLATFORM_IRQ_TOTALCOUNT]={0};
//fLib_INT IRQVector[64]={0};
UINT32 IRQSources = 0;//define the current irq source for debug


volatile int is_enter_irq = 0; 
  
/* define IRQ trap and handler routine */
//PrVoid fLib_NewIRQTrap = (PrVoid) 0;	
//PrHandler fLib_IRQHandle = (PrHandler) 0;
//PrVoid fLib_OldIRQTrap = (PrVoid) 0;	

#if NR_IRQS > PLATFORM_IRQ_TOTALCOUNT
#  error Unable to handle more than 64 IRQ levels.
#endif

/////////////////////////////////////////////////////
//
//	Only for detail function call subroutine
//
/////////////////////////////////////////////////////

/*
 * Turn the interrupt source off. */
void MaskIRQ(UINT32 IRQ)
{    
	if(IRQ >=32)
	{
		IRQ-=32;
		IRQBase[(EXT_IRQ_MASK / sizeof(UINT32))] &= ~(1 << IRQ);
	}	
	else
	{
	    IRQBase[(IRQ_MASK / sizeof(UINT32))] &= ~(1 << IRQ);
	}
}

/*  Turn the interrupt source on. */
void UnmaskIRQ(UINT32 IRQ)
{    
	
	if(IRQ >=32)
	{
		IRQ-=32;
	    IRQBase[(EXT_IRQ_MASK / sizeof(UINT32))] |= (1 << IRQ);
	}    
	else    
	{
	    IRQBase[(IRQ_MASK / sizeof(UINT32))] |= (1 << IRQ);
	}
	
}
void SetIRQmode(UINT32 IRQ,UINT32 edge)
{	
    if(IRQ>=32)
    {
    	IRQ-=32;
    	if(edge) 
	    	IRQBase[(EXT_IRQ_MODE / sizeof(UINT32))] |= (1 << IRQ);
    	else
    		IRQBase[(EXT_IRQ_MODE / sizeof(UINT32))] &= ~(1 << IRQ);	
    }
    else
    {
	    if(edge) 
    		IRQBase[(IRQ_MODE / sizeof(UINT32))] |= (1 << IRQ);
	    else
    		IRQBase[(IRQ_MODE / sizeof(UINT32))] &= ~(1 << IRQ);	
    }
}	

void SetIRQlevel(UINT32 IRQ,UINT32 low)
{	
    if(IRQ>=32)
    {
    	IRQ-=32;
	     if(low) 
    		IRQBase[(EXT_IRQ_LEVEL / sizeof(UINT32))] |= (1 << IRQ);
	    else
    		IRQBase[(EXT_IRQ_LEVEL / sizeof(UINT32))] &= ~(1 << IRQ);	
    }
    else
    {
	    if(low) 
    		IRQBase[(IRQ_LEVEL / sizeof(UINT32))] |= (1 << IRQ);
	    else
    		IRQBase[(IRQ_LEVEL / sizeof(UINT32))] &= ~(1 << IRQ);	
    }
}	
void ClearIRQStatus(UINT32 IRQ)
{
 	if(IRQ>=32)
	{
		IRQ-=32;
		IRQBase[(EXT_IRQ_CLEAR / sizeof(UINT32))] |= (1 << IRQ);
	}	
	else 	
	{
	 	IRQBase[(IRQ_CLEAR / sizeof(UINT32))] |= (1 << IRQ);
	}
}

int get_irqnum(UINT32 flags)
{
	int IRQ = 0;
	
	if ((flags & 0xffff) == 0)
    {
        IRQ += 16;
        flags >>= 16;
    }

    if ((flags & 0xff) == 0)
    {
        IRQ += 8;
        flags >>= 8;
    }

    if ((flags & 0xf) == 0)
    {
        IRQ += 4;
        flags >>= 4;
    }

    if ((flags & 0x3) == 0)
    {
        IRQ += 2;
        flags >>= 2;
    }

    if ((flags & 0x1) == 0)
    {
        IRQ += 1;
        flags >>= 1;
    }
    return IRQ;
}

//void __attribute__((naked)) DispatchIRQ(void)
//void __attribute__((interrupt("IRQ"))) DispatchIRQ(void)
void DispatchIRQ(void)
{
    unsigned int irq = 0;
    fLib_INT *action;
    UINT32 int_status;
    UINT32  status;

	is_enter_irq++;
    int_status = inw(INTC_FTINTC020_PA_BASE + IRQ_STATUS);
    //fLib_printf("int_status = 0x%08x.\n", int_status);
    for(irq = 0; int_status && irq < 32; irq++){
       status = int_status & 0x1;
       int_status >>= 1;
        if(status){
            action = &IRQVector[irq];
            if(action->Handler) {
                action->Handler(action->IntNum);
            }
            fLib_ClearInt(irq);
        }
    }
    
    int_status = inw(INTC_FTINTC020_PA_BASE + EXT_IRQ_STATUS);
    //fLib_printf("ext_int_status = 0x%08x.\n", int_status);
    for(irq = 32; int_status && irq < 64; irq++){
       status = int_status & 0x1;
       int_status >>= 1;
        if(status){
            action = &IRQVector[irq];
            if(action->Handler) {
                action->Handler(action->IntNum);
            }
            fLib_ClearInt(irq);
        }
    }

	is_enter_irq--;
    return ;
}

/*************************************/
/* Start of Vector-related functions */
/*************************************/
void ClearPrioMask(UINT32 VIC)
{
	IRQBase[(SEL_VECTADDR / sizeof(UINT32))] = (1 << VIC);
}
	
void SetVectAddr(UINT32 vectnum, UINT32 addr)
{				
   	IRQBase[(VECT_ADDR0 / sizeof(UINT32)) + vectnum] = addr;
}	
	
UINT32 GetVectAddr(UINT32 vectnum)
{
   	return IRQBase[(VECT_ADDR0 / sizeof(UINT32)) + vectnum];
}	

void SetVectAddrCtrl(UINT32 vectnum, UINT32 val)
{
	IRQBase[(VECT_ADDRCTRL0 / sizeof(UINT32)) + vectnum] = val;	
}
			   
UINT32 GetVectAddrCtrl(UINT32 vectnum)
{
	return IRQBase[(VECT_ADDRCTRL0 / sizeof(UINT32)) + vectnum];
}

void SetDefVectAddr(UINT32 addr)
	{
  	IRQBase[(DEF_VECTADDR / sizeof(UINT32))] = addr;
}	

void EnableVectInt(void)
		{
	IRQBase[(INT_PRIARBCTRL / sizeof(UINT32))] =  ROUND_ROBIN;	
		}

void DisableVectInt(void)
{
	IRQBase[(INT_PRIARBCTRL / sizeof(UINT32))] = 0x0;	
}
/* End of Vector-related functions */

 // End of file - IRQ.c
